﻿//C++ code

namespace Duelo3DCode
{
	void cMapa::RecalculaAfinamento(ushort x, ushort y, ushort z)
	{
		//### Chão
		cAfin afinamentochao(cAfin::AFIN_MASK_DEFAULT);
		if (z > 0) {
			int pos = VetPos(x, y, z - 1);
			cChao chao = contchao[pos];

			if (!chao.EhChaoBuraco()) {
				//|     0
				//| 5  ___  1
				//|   /   \
				//|   \___/
				//| 4       2
				//|     3
				//TO DO: falta o caso (0-2-3 OU 0-1-2-3)
				cChao cvizinho[6];
				short h = (x % 2);
				cvizinho[0] = Chao(    x, y + 1,		z);
				cvizinho[3] = Chao(    x, y - 1,		z);

				cvizinho[1] = Chao(x + 1, y + h,		z);
				cvizinho[2] = Chao(x + 1, y - 1 + h,	z);

				cvizinho[5] = Chao(x - 1, y + h,		z);
				cvizinho[4] = Chao(x - 1, y - 1 + h,	z);

				bool vizinho[6];
				int contvizinhos = 0;
				for (int i=0; i<6; i++) {
					if (cvizinho[i].EhForaDoMapa()) {
						vizinho[i] = 0;
					} else {
						vizinho[i] = !cvizinho[i].EhChaoBuraco(); //TO DO: testar se é do mesmo tipo de parede
					}
					if (vizinho[i]) contvizinhos++;
				}
				
				afinchao[pos] = cAfin::CriaPelosVizinhos(contvizinhos, vizinho);
				afinamentochao = afinchao[pos];
			} else {
				afinchao[pos] = cAfin::AFIN_MASK_DEFAULT;
			}
		}

		//### Cont
		int pos = VetPos(x, y, z);
		cCont conteudo = cont[pos];

		if (conteudo.EhParedeSolida()) {
			if (!afinamentochao.EhAfinInteira()) {
				//caso o chão seja afinado, a parede de cima herda
				afin[pos] = afinamentochao;
			} else {
				//|     0
				//| 5  ___  1
				//|   /   \
				//|   \___/
				//| 4       2
				//|     3
				//TO DO: falta o caso (0-2-3 OU 0-1-2-3)
				cCont cvizinho[6];
				short h = (x % 2);
				cvizinho[0] = Cont(    x, y + 1,		z);
				cvizinho[3] = Cont(    x, y - 1,		z);

				cvizinho[1] = Cont(x + 1, y + h,		z);
				cvizinho[2] = Cont(x + 1, y - 1 + h,	z);

				cvizinho[5] = Cont(x - 1, y + h,		z);
				cvizinho[4] = Cont(x - 1, y - 1 + h,	z);

				bool vizinho[6];
				int contvizinhos = 0;
				for (int i=0; i<6; i++) {
					if (cvizinho[i].EhForaDoMapa()) {
						vizinho[i] = 0;
					} else {
						vizinho[i] = cvizinho[i].EhParedeSolida(); //TO DO: testar se é do mesmo tipo de parede	
					}
					if (vizinho[i]) contvizinhos++;
				}
				
				afin[pos] = cAfin::CriaPelosVizinhos(contvizinhos, vizinho);
			}
		} else {
			afin[pos] = cAfin::AFIN_MASK_DEFAULT;
		}
	}

	bool cCont::EhParedeSolida(char c)
	{
		if (EhPortaAberta(c)) return false;
		c &= CONT_MASK_TIPO_PAREDE;
		return c == CONT_PAREDE_MADEIRA ||
			   c == CONT_PAREDE_TIJOLO ||
			   c == CONT_PAREDE_PEDRA ||
			   c == CONT_PAREDE_VIDRO ||
			   c == CONT_PAREDE_GRADE;
	}

	class cAfin
	{
		enum
		{
			AFIN_MASK_DEFAULT	= 0,
		
			AFIN_MASK_TIPO	= (char)0x30, //0011 0000
			AFIN_INTEIRO	= (char)0x00,
			AFIN_ATRAVES	= (char)0x10,
			AFIN_METADE		= (char)0x20,

			AFIN_MASK_ROT	= (char)0x07, //0000 0111
			AFIN_ROT_0		= (char)0x00,
			AFIN_ROT_1		= (char)0x01,
			AFIN_ROT_2		= (char)0x02,
			AFIN_ROT_3		= (char)0x03,
			AFIN_ROT_4		= (char)0x04,
			AFIN_ROT_5		= (char)0x05,
		};

		char cAfin::CriaPelosVizinhos(int contvizinhos, bool vizinho[6])
		{
			if (contvizinhos == 1) {
				for (char i=0; i<6; i++) {
					if (vizinho[i]) {
						return cAfin::AFIN_ATRAVES + i;
						break;
					}
				}
			} else if (contvizinhos == 2) {
				if (vizinho[0] && vizinho[3]) {
					return cAfin::AFIN_ATRAVES;
				} else if (vizinho[1] && vizinho[4]) {
					return cAfin::AFIN_ATRAVES + 1;
				} else if (vizinho[2] && vizinho[5]) {
					return cAfin::AFIN_ATRAVES + 2;

				} else if (vizinho[5] && vizinho[1]) {
					return cAfin::AFIN_METADE;
				} else if (vizinho[0] && vizinho[2]) {
					return cAfin::AFIN_METADE + 1;
				} else if (vizinho[1] && vizinho[3]) {
					return cAfin::AFIN_METADE + 2;
				} else if (vizinho[2] && vizinho[4]) {
					return cAfin::AFIN_METADE + 3;
				} else if (vizinho[3] && vizinho[5]) {
					return cAfin::AFIN_METADE + 4;
				} else if (vizinho[4] && vizinho[0]) {
					return cAfin::AFIN_METADE + 5;
				}
			} else if (contvizinhos == 3) {
				if (vizinho[5] && vizinho[0] && vizinho[1]) {
					return cAfin::AFIN_METADE;
				} else if (vizinho[0] && vizinho[1] && vizinho[2]) {
					return cAfin::AFIN_METADE + 1;
				} else if (vizinho[1] && vizinho[2] && vizinho[3]) {
					return cAfin::AFIN_METADE + 2;
				} else if (vizinho[2] && vizinho[3] && vizinho[4]) {
					return cAfin::AFIN_METADE + 3;
				} else if (vizinho[3] && vizinho[4] && vizinho[5]) {
					return cAfin::AFIN_METADE + 4;
				} else if (vizinho[4] && vizinho[5] && vizinho[0]) {
					return cAfin::AFIN_METADE + 5;
				}
			}
			return cAfin::AFIN_MASK_DEFAULT;
		}

		bool cAfin::EhAfinInteira(char c)	{return (c & AFIN_MASK_TIPO) == AFIN_INTEIRO;}
		bool cAfin::EhAfinAtraves(char c)	{return (c & AFIN_MASK_TIPO) == AFIN_ATRAVES;}
		bool cAfin::EhAfinMetade(char c)	{return (c & AFIN_MASK_TIPO) == AFIN_METADE;}
		float cAfin::AfinRotacao(char c)	{return 60 * (float)(c & AFIN_MASK_ROT);}
	}
}